package de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.tests;
import static org.junit.Assert.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.data.MultinomialOnlyCorpus;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.data.Word;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.datacreation.CSVTokenizer;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.datacreation.CreateFeatures;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.datacreation.CreateGraph;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.datacreation.FeatureType;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.datacreation.feature_types.CaseFeatures;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.datacreation.feature_types.PunctuationFeatures;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.datacreation.feature_types.SuffixFeatures;
import de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.model.MultinomialWithLexicon;
/**
 * 
 * @author Christoph Teichmann
 *
 */
public class TestMultinomialWithLexicon
{
	/**
	 * 
	 */
	private MultinomialOnlyCorpus wc;
	/**
	 * 
	 */
	private MultinomialWithLexicon mwl;
	@Before
	public void setUp() throws Exception
	{
		wc = new MultinomialOnlyCorpus();
		FeatureType[] ft = new FeatureType[] {new SuffixFeatures(2),new PunctuationFeatures(),
				new CaseFeatures()};
		makeFeaturePart(ft,wc);	
		mwl = new MultinomialWithLexicon(wc, 0.2, 12, 1.3, 4.1, 2.2);
		mwl.initialize();
	}
	/**
	 * 
	 * @param ft
	 * @param wc 
	 * @throws IOException
	 */
	private void makeFeaturePart(FeatureType[] ft, MultinomialOnlyCorpus wc) throws IOException
	{
		CreateFeatures cf = new CreateFeatures(ft);
		StringReader sr = new StringReader(TestStrings.ALIGNMENTS);
		BufferedReader br = new BufferedReader(sr);
		cf.addFeatures(br, new CSVTokenizer(false));
		br.close();
		addFeatureLexicon(ft,cf,wc);
		addWords(cf,ft,wc);
	}
	/**
	 * 
	 * @param cf
	 * @param ft 
	 * @param wc 
	 * @throws IOException
	 */
	private void addWords(CreateFeatures cf, FeatureType[] ft, MultinomialOnlyCorpus wc) throws IOException
	{
		StringReader sr;
		BufferedReader br;
		StringWriter sw = new StringWriter();
		BufferedWriter bw = new BufferedWriter(sw);
		cf.writeOutFeatures(bw);
		bw.close();
		sr = new StringReader(sw.toString());
		br = new BufferedReader(sr);
		CreateGraph cg = new CreateGraph(true, false, ft);
		StringReader sb = new StringReader(TestStrings.ALIGNMENTS);
		BufferedReader bb = new BufferedReader(sb);
		cg.addAlignments(bb);
		bb.close();
		StringWriter sc = new StringWriter();
		BufferedWriter bc = new BufferedWriter(sc);
		cg.writeOutEdges(bc);
		bc.close();
		sb = new StringReader(sc.toString());
		bb = new BufferedReader(sb);
		wc.addWordsAndConnections(br, bb);
		br.close();
	}
	/**
	 * 
	 * @param ft
	 * @param cf
	 * @param wc 
	 * @throws IOException
	 */
	private void addFeatureLexicon(FeatureType[] ft, CreateFeatures cf, MultinomialOnlyCorpus wc) throws IOException
	{
		StringWriter sw = new StringWriter();
		BufferedWriter bw = new BufferedWriter(sw);
		cf.writeOutFeatureLexicon(bw);
		bw.close();
		StringReader sr = new StringReader(sw.toString());
		BufferedReader br = new BufferedReader(sr);
		wc.addFeatures(br);
	}
	@Test
	public void testIterator()
	{
		Set<Word> s = new HashSet<>();
		for(Word w : this.mwl)
		{s.add(w);}
		assertTrue(s.size() > 0);
		for(Word w : this.wc)
		{
			assertTrue(s.contains(w));
			s.remove(w);
		}
		assertEquals(s.size(), 0);
	}
	@Test
	public void testGetNumberOfLabels()
	{assertEquals(this.mwl.getNumberOfLabels(wc.iterator().next()),12);}
	@Test
	public void testMakeLogLikelihood() throws IOException
	{
		Word q = null;
		Word right = null;
		Word before = null;
		Word after = null;
		for(Word w : this.wc)
		{
			if(this.wc.getName(w.getIdentity()).equals("hund"))
			{q = w;}
			else if(this.wc.getName(w.getIdentity()).equals("dogs"))
			{right = w;}
			else if(this.wc.getName(w.getIdentity()).equals("ein"))
			{before = w;}
			else if(this.wc.getName(w.getIdentity()).equals("lebt"))
			{after = w;}
		}
		this.mwl.setTag(after, 1);
		this.mwl.setTag(before, 2);
		this.mwl.setTag(right, 2);
		assertFalse(q == null);
		mwl.setTag(q, 1);
		assertEquals(this.mwl.makeLogProbability(q, 2),-14.822864281395326,0.00000001);
		mwl.setTag(q, 2);
		assertEquals(this.mwl.makeLogProbability(q, 2),-11.988352979999416,0.00000001);
		mwl.setTag(q, 1);
		assertEquals(this.mwl.makeLogProbability(q, 2),-14.822864281395326,0.00000001);
		int k=0;
		for(Word w : mwl)
		{
			assertEquals(mwl.getNumberOfLabels(w),12);
			for(int i=0;i<mwl.getNumberOfLabels(w);++i)
			{
				double d = Double.NaN;
				assertFalse(Double.isInfinite(d = mwl.makeLogProbability(w, i%12)));
				assertFalse(Double.isNaN(d));
			}
			mwl.setTag(w, (k++)%12);
		}
		double d = 0;
		for(Word w : mwl)
		{
			assertEquals(mwl.getNumberOfLabels(w),12);
			assertFalse(Double.isInfinite(d += this.mwl.makeLogProbability(w,this.mwl.getTag(w))));
			assertFalse(Double.isNaN(d));
		}
		assertEquals(d,mwl.makeLogLikelihood(),0.00000001);
		for(Word w : mwl)
		{this.mwl.setTag(w, 2);}
		StringWriter sw = new StringWriter();
		BufferedWriter bw = new BufferedWriter(sw);
		this.mwl.writeOutTags(bw);
		bw.close();
		String[] parts = sw.toString().split("\n");
		Set<String> set = new HashSet<>();
		for(String s : parts)
		{set.add(s);}
		assertTrue(set.contains("Language: ENGLISH Word: automotive tag: 2"));
	}
}